package jinyilw.common.ffmpeg;

import jinyilw.common.ExecuteTools;
import jinyilw.common.TextTools;
import jinyilw.common.file.FileTools;
import jinyilw.common.log.LogTools;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FFmpegTools
{
	private static File ffmpegFile = FileTools.getUserFile("ffmpeg");
	private static String ffmpegPath = ffmpegFile.getAbsolutePath();
	private static boolean isExecutable = executable();
	/**
	 * 可以处理的视频格式
	 */
	public final static String[] VIDEO_TYPE = {"MP4", "AVI", "WMV"};
	/**
	 * 可以处理的图片格式
	 */
	public final static String[] IMAGE_TYPE = {"JPG", "JPEG", "PNG", "GIF"};
	/**
	 * 可以处理的音频格式
	 */
	public final static String[] AUDIO_TYPE = {"AAC"};

	/**
	 * 视频时长正则匹配式 用于解析视频及音频的时长等信息时使用；
	 * <p>
	 * (.*?)表示：匹配任何除\r\n之外的任何0或多个字符，非贪婪模式
	 */
	private static final String durationRegex =
			"Duration: (\\d*?):(\\d*?):(\\d*?)\\.(\\d*?), start: ("
					+ ".*?), bitrate: (\\d*) kb\\/s.*";
	private static Pattern durationPattern;
	/**
	 * 视频流信息正则匹配式 用于解析视频详细信息时使用；
	 */
	private static final String videoStreamRegex = "Stream #\\d:\\d[(]??\\S*[)]??: Video: "
			+ "(\\S*\\S$?)[^,]*, (.*?), (\\d*)x(\\d*)[^,]*, (\\d*) kb/s, (\\d*[.]??\\d*) "
			+ "fps";
	private static Pattern videoStreamPattern;
	/**
	 * 音频流信息正则匹配式 用于解析音频详细信息时使用；
	 */
	private static final String musicStreamRegex = "Stream #\\d:\\d[(]??\\S*[)]??: Audio: "
			+ "(\\S*\\S$?)(.*), (.*?) Hz, (.*?), (.*?), (\\d*) kb/s";
	private static Pattern musicStreamPattern;

	public static Pattern getDurationPattern()
	{
		if (durationPattern == null)
			durationPattern = Pattern.compile(durationRegex);
		return durationPattern;
	}

	public static Pattern getVideoStreamPattern()
	{
		if (videoStreamPattern == null)
			videoStreamPattern = Pattern.compile(videoStreamRegex);
		return videoStreamPattern;
	}

	public static Pattern getMusicStreamPattern()
	{
		if (musicStreamPattern == null)
			musicStreamPattern = Pattern.compile(musicStreamRegex);
		return musicStreamPattern;
	}

	public static File getFFmpegFile()
	{
		return ffmpegFile;
	}

	/**
	 * 获取当前多媒体处理工具内的ffmpeg的执行路径
	 */
	public static String getFFmpegPath()
	{
		return ffmpegPath;
	}

	/**
	 * 设置当前多媒体工具内的ffmpeg的执行路径
	 *
	 * @param path ffmpeg可执行程序在实际系统中的绝对路径
	 */
	public static boolean setFFmpegPath(String path)
	{
		if (TextTools.isBlank(path))
		{
			LogTools.error("--- 设置ffmpeg执行路径失败，因为传入的ffmpeg可执行程序路径为空！ ---");
			return false;
		}
		return setFFmpegFile(new File(path));
	}

	public static boolean setFFmpegFile(File file)
	{
		if (file == null || !file.isFile())
		{
			LogTools.error("--- 设置ffmpeg执行路径失败，因为传入的ffmpeg文件不存在！ ---");
			return false;
		}
		ffmpegFile = file;
		ffmpegPath = file.getAbsolutePath();
		isExecutable = executable();
		if (isExecutable)
			LogTools.info(
					"--- 设置ffmpeg执行路径成功 --- 当前ffmpeg可执行程序路径为： " + ffmpegPath);
		else
		{
			LogTools.error("--- 设置ffmpeg执行路径成功，但不是可执行文件！---");
			return false;
		}
		return true;
	}

	/**
	 * 测试当前多媒体工具是否可以正常工作
	 */
	private static boolean executable()
	{
		File ffmpegFile = new File(ffmpegPath);
		if (!ffmpegFile.isFile())
		{
			LogTools.error(
					"--- 工作状态异常，因为传入的ffmpeg可执行程序路径下的ffmpeg文件不存在！ ---");
			return false;
		}
		String ffmpegVersionStr = ExecuteTools.execute(ffmpegPath + " -version");
		if (TextTools.isBlank(ffmpegVersionStr))
		{
			LogTools.error("--- 工作状态异常，因为ffmpeg命令执行失败！ ---");
			return false;
		}
		LogTools.info("--- 工作状态正常 ---");
		return true;
	}

	public static boolean isExecutable()
	{
		return isExecutable;
	}

	/**
	 * 执行FFmpeg命令
	 *
	 * @param commands 要执行的FFmpeg命令
	 * @return FFmpeg程序在执行命令过程中产生的各信息，执行出错时返回null
	 */
	public static String executeCommand(List<String> commands)
	{
		if (commands == null || commands.isEmpty())
		{
			LogTools.error("--- 指令执行失败，因为要执行的FFmpeg指令为空！ ---");
			return null;
		}
		if (!isExecutable)
		{
			LogTools.error("--- 指令执行失败，因为FFmpeg不是可执行文件！ ---");
			return null;
		}
		LinkedList<String> ffmpegCommands = new LinkedList<>(commands);
		ffmpegCommands.addFirst(ffmpegPath); // 设置ffmpeg程序所在路径
		LogTools.info("--- 待执行的FFmpeg指令为：---" + ffmpegCommands);

		Process ffmpeg = null;
		try
		{
			// 执行ffmpeg指令
			ProcessBuilder builder = new ProcessBuilder();
			builder.command(ffmpegCommands);
			ffmpeg = builder.start();
			LogTools.info("--- 开始执行FFmpeg指令：--- 执行线程名：" + builder);

			// 取出输出流和错误流的信息
			// 注意：必须要取出ffmpeg在执行命令过程中产生的输出信息，如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时，线程就回阻塞住
			PrintStream errorStream = new PrintStream(ffmpeg.getErrorStream());
			PrintStream inputStream = new PrintStream(ffmpeg.getInputStream());
			errorStream.start();
			inputStream.start();
			// 等待ffmpeg命令执行完
			ffmpeg.waitFor();

			// 获取执行结果字符串
			String result = errorStream.stringBuffer
					.append(inputStream.stringBuffer).toString();

			// 输出执行的命令信息
			String cmdStr = Arrays.toString(ffmpegCommands.toArray()).replace(",",
					"");
			String resultStr = TextTools.isBlank(result) ? "【异常】" : "正常";
			LogTools.info("--- 已执行的FFmpeg命令： ---" + cmdStr + " 已执行完毕,执行结果： "
					+ resultStr);
			return result;

		} catch (Exception e)
		{
			LogTools.error("--- FFmpeg命令执行出错！ --- 出错信息： " + e.getMessage());
			return null;

		} finally
		{
			ExecuteTools.killWhenExitApp(ffmpeg);
		}
	}

	public static void convertVideo(File videoFile, boolean keepAudio,
			File audioFile, File outputFile, int crf, String preset, int width,
			int height)
	{
		if (!isExecutable)
			throw new RuntimeException("FFmpeg文件不可执行");
		if (null == videoFile || !videoFile.exists())
		{
			throw new RuntimeException("源视频文件不存在，请检查源视频路径");
		}
		if (null == outputFile)
		{
			throw new RuntimeException("转换后的视频路径为空，请检查转换后的视频存放路径是否正确");
		}

		if (!outputFile.exists())
		{
			try
			{
				outputFile.createNewFile();
			} catch (IOException e)
			{
				LogTools.error("视频转换时新建输出文件失败");
			}
		}

		String format = TextTools.getFileExt(videoFile.getName());
		if (!isLegalFormat(format, VIDEO_TYPE))
		{
			throw new RuntimeException("无法解析的视频格式：" + format);
		}

		List<String> command = new ArrayList<>();
		command.add("-i");
		command.add(videoFile.getAbsolutePath());
		if (audioFile != null && audioFile.isFile())
		{
			command.add("-i");
			command.add(audioFile.getAbsolutePath());
		}
		if (!keepAudio)
			command.add("-an"); // 去掉音频

		if (width > 0 && height > 0)
		{ // 设置分辨率
			command.add("-s");
			String resolution = width + "x" + height;
			command.add(resolution);
		}

		command.add("-vcodec"); // 指定输出视频文件时使用的编码器
		command.add("libx264"); // 指定使用x264编码器
		command.add("-preset"); // 当使用x264时需要带上该参数
		command.add(preset); // 指定preset参数
		command.add("-crf"); // 指定输出视频质量
		command.add(String.valueOf(crf)); // 视频质量参数，值越小视频质量越高
		command.add("-y"); // 当已存在输出文件时，不提示是否覆盖
		command.add(outputFile.getAbsolutePath());

		executeCommand(command);
	}

	/**
	 * 视频转换
	 * <p>
	 * 注意指定视频分辨率时，宽度和高度必须同时有值；
	 *
	 * @param inputFile  源视频路径
	 * @param outputFile 转换后的视频输出路径
	 * @param withAudio  是否保留音频；true-保留，false-不保留
	 * @param crf        指定视频的质量系数（值越小，视频质量越高，体积越大；该系数取值为0-51，直接影响视频码率大小）,取值参考：CrfValueEnum.code
	 * @param preset     指定视频的编码速率（速率越快压缩率越低），取值参考：PresetValueEnum.presetValue
	 * @param width      视频宽度；为空则保持源视频宽度
	 * @param height     视频高度；为空则保持源视频高度
	 */
	public static void convertVideo(File inputFile, File outputFile,
			boolean withAudio, int crf, String preset, int width, int height)
	{
		convertVideo(inputFile, withAudio, null, outputFile, crf, preset, width,
				height);
	}

	public static void convertVideo(File inputFile, File outputFile,
			boolean withAudio, int crf, String speed)
	{
		convertVideo(inputFile, outputFile, withAudio, crf, speed, 0, 0);
	}

	public static void convertVideo(File videoFile, boolean keepAudio,
			File audioFile, File outputFile, int crf, String speed)
	{
		convertVideo(videoFile, keepAudio, audioFile, outputFile, crf, speed, 0,
				0);
	}

	public static void convertVideo(File inputFile, File outputFile,
			boolean withAudio, CrfValueEnum mediaQuality,
			PresetVauleEnum mediaZipSpeed, int width, int height)
	{
		convertVideo(inputFile, outputFile, withAudio, mediaQuality.getCode(),
				mediaZipSpeed.getPresetValue(), width, height);
	}

	public static void convertHighQualityVideo(File inputFile, File outputFile,
			boolean withAudio, int width, int height)
	{
		convertVideo(inputFile, outputFile, withAudio, 23, "slower", width,
				height);
	}

	/**
	 * 截取视频中的某一段，生成新视频
	 *
	 * @param videoFile  源视频路径
	 * @param outputFile 转换后的视频路径
	 * @param startTime  开始抽取的时间点（单位:s）
	 * @param timeLength 需要抽取的时间段（单位:s，需小于源视频最大时长）；例如：该参数值为10时即抽取从startTime开始之后10秒内的视频作为新视频
	 */
	public static void cutVideo(File videoFile, File outputFile, Time startTime,
			int timeLength)
	{
		if (videoFile == null || !videoFile.exists())
		{
			throw new RuntimeException("视频文件不存在：");
		}
		if (null == outputFile)
		{
			throw new RuntimeException("转换后的视频路径为空，请检查转换后的视频存放路径是否正确");
		}
		VideoMetaInfo info = getVideoMetaInfo(videoFile);
		if (null == info)
		{
			throw new RuntimeException("未解析到视频信息");
		}
		if (startTime.getTime() + timeLength > info.getDuration())
		{
			throw new RuntimeException(
					"截取时间不合法：" + startTime + "，因为截取时间大于视频的时长");
		}
		try
		{
			if (!outputFile.exists())
			{
				outputFile.createNewFile();
			}
			List<String> command = new ArrayList<>();
			command.add("-ss");
			command.add(startTime.toString());
			command.add("-t");
			command.add("" + timeLength);
			command.add("-i");
			command.add(videoFile.getAbsolutePath());
			command.add("-vcodec");
			command.add("copy");
			command.add("-acodec");
			command.add("copy");
			command.add(outputFile.getAbsolutePath());
			executeCommand(command);
		} catch (IOException e)
		{
			LogTools.error("--- 视频截取过程出错 ---");
		}
	}

	/**
	 * 抽取视频里的音频信息 只能抽取成MP3文件
	 *
	 * @param videoFile 源视频文件
	 * @param audioFile 从源视频提取的音频文件
	 */
	public static void getAudioFromVideo(File videoFile, File audioFile)
	{
		if (null == videoFile || !videoFile.exists())
		{
			throw new RuntimeException("源视频文件不存在： ");
		}
		if (null == audioFile)
		{
			throw new RuntimeException("要提取的音频路径为空：");
		}
		String format = TextTools.getFileExt(audioFile.getName());
		if (!isLegalFormat(format, AUDIO_TYPE))
		{
			throw new RuntimeException(
					"无法生成指定格式的音频：" + format + " 请检查要输出的音频文件是否是AAC类型");
		}
		try
		{
			if (!audioFile.exists())
			{
				audioFile.createNewFile();
			}

			List<String> commands = new ArrayList<>();
			commands.add("-i");
			commands.add(videoFile.getAbsolutePath());
			commands.add("-vn"); // no video，去除视频信息
			commands.add("-y");
			commands.add("-acodec");
			commands.add("copy");
			commands.add(audioFile.getAbsolutePath());
			executeCommand(commands);
		} catch (Exception e)
		{
			LogTools.error("--- 抽取视频中的音频信息的过程出错 --- 错误信息： " + e.getMessage());
		}
	}

	/**
	 * 解析视频的基本信息（从文件中）
	 *
	 * @param videoFile 源视频路径
	 * @return 视频的基本信息，解码失败时返回null
	 */
	public static VideoMetaInfo getVideoMetaInfo(File videoFile)
	{
		if (null == videoFile || !videoFile.exists())
		{
			LogTools.error("--- 解析视频信息失败，因为要解析的源视频文件不存在 ---");
			return null;
		}

		String parseResult = getMetaInfoFromFFmpeg(videoFile);

		Matcher durationMatcher = getDurationPattern().matcher(parseResult);
		Matcher videoStreamMatcher = getVideoStreamPattern()
				.matcher(parseResult);
		Matcher videoMusicStreamMatcher = getMusicStreamPattern()
				.matcher(parseResult);

		long duration = 0L; // 视频时长
		int videoBitrate = 0; // 视频码率
		String videoFormat = TextTools.getFileExt(videoFile.getName()); // 视频格式
		Long videoSize = videoFile.length(); // 视频大小

		String videoEncoder = ""; // 视频编码器
		int videoHeight = 0; // 视频高度
		int videoWidth = 0; // 视频宽度
		float videoFramerate = 0F; // 视频帧率

		String musicFormat = ""; // 音频格式
		long samplerate = 0L; // 音频采样率
		int musicBitrate = 0; // 音频码率

		try
		{
			// 匹配视频播放时长等信息
			if (durationMatcher.find())
			{
				long hours = Integer.parseInt(durationMatcher.group(1));
				long minutes = Integer.parseInt(durationMatcher.group(2));
				long seconds = Integer.parseInt(durationMatcher.group(3));
				long dec = Integer.parseInt(durationMatcher.group(4));
				duration = dec * 100L + seconds * 1000L + minutes * 60L * 1000L
						+ hours * 60L * 60L * 1000L;
				// String startTime = durationMatcher.group(5) + "ms";
				videoBitrate = Integer.parseInt(durationMatcher.group(6));
			}
			// 匹配视频分辨率等信息
			if (videoStreamMatcher.find())
			{
				videoEncoder = videoStreamMatcher.group(1);
				String s2 = videoStreamMatcher.group(2);
				videoWidth = Integer.parseInt(videoStreamMatcher.group(3));
				videoHeight = Integer.parseInt(videoStreamMatcher.group(4));
				String s5 = videoStreamMatcher.group(5);
				videoFramerate = Float.parseFloat(videoStreamMatcher.group(6));
			}
			// 匹配视频中的音频信息
			if (videoMusicStreamMatcher.find())
			{
				musicFormat = videoMusicStreamMatcher.group(1); // 提取音频格式
				// String s2 = videoMusicStreamMatcher.group(2);
				samplerate = Long.parseLong(videoMusicStreamMatcher.group(3)); // 提取采样率
				// String s4 = videoMusicStreamMatcher.group(4);
				// String s5 = videoMusicStreamMatcher.group(5);
				musicBitrate = Integer
						.parseInt(videoMusicStreamMatcher.group(6)); // 提取比特率
			}
		} catch (Exception e)
		{
			LogTools.error("--- 解析视频参数信息出错！ --- 错误信息： " + e.getMessage());
			return null;
		}

		// 封装视频中的音频信息
		MusicMetaInfo musicMetaInfo = new MusicMetaInfo();
		musicMetaInfo.setFormat(musicFormat);
		musicMetaInfo.setDuration(duration);
		musicMetaInfo.setBitRate(musicBitrate);
		musicMetaInfo.setSampleRate(samplerate);
		// 封装视频信息
		VideoMetaInfo videoMetaInfo = new VideoMetaInfo();
		videoMetaInfo.setFormat(videoFormat);
		videoMetaInfo.setSize(videoSize);
		videoMetaInfo.setBitRate(videoBitrate);
		videoMetaInfo.setDuration(duration);
		videoMetaInfo.setEncoder(videoEncoder);
		videoMetaInfo.setFrameRate(videoFramerate);
		videoMetaInfo.setHeight(videoHeight);
		videoMetaInfo.setWidth(videoWidth);
		videoMetaInfo.setMusicMetaInfo(musicMetaInfo);

		return videoMetaInfo;
	}

	/**
	 * 获取视频的基本信息（从流中）
	 *
	 * @param inputStream 源视频流路径
	 * @return 视频的基本信息，解码失败时返回null
	 */
	public static VideoMetaInfo getVideoMetaInfo(InputStream inputStream)
	{
		VideoMetaInfo videoInfo = new VideoMetaInfo();
		try
		{
			File file = File.createTempFile("tmp", null);
			if (!file.exists())
			{
				return null;
			}
			FileTools.copyInputStreamToFile(inputStream, file);
			videoInfo = getVideoMetaInfo(file);
			file.deleteOnExit();
			return videoInfo;
		} catch (Exception e)
		{
			LogTools.error("--- 从流中获取视频基本信息出错 --- 错误信息： " + e.getMessage());
			return null;
		}
	}

	/**
	 * 获取音频的基本信息（从文件中）
	 *
	 * @param musicFile 音频文件路径
	 * @return 音频的基本信息，解码失败时返回null
	 */
	public static MusicMetaInfo getMusicMetaInfo(File musicFile)
	{
		if (null == musicFile || !musicFile.exists())
		{
			LogTools.error("--- 无法获取音频信息，因为要解析的音频文件为空 ---");
			return null;
		}
		// 获取音频信息字符串，方便后续解析
		String parseResult = getMetaInfoFromFFmpeg(musicFile);

		long duration = 0L; // 音频时长
		int musicBitrate = 0; // 音频码率
		long samplerate = 0L; // 音频采样率
		String musicFormat = ""; // 音频格式
		Long musicSize = musicFile.length(); // 音频大小

		Matcher durationMatcher = getDurationPattern().matcher(parseResult);
		Matcher musicStreamMatcher = getMusicStreamPattern()
				.matcher(parseResult);

		try
		{
			// 匹配音频播放时长等信息
			if (durationMatcher.find())
			{
				long hours = Integer.parseInt(durationMatcher.group(1));
				long minutes = Integer.parseInt(durationMatcher.group(2));
				long seconds = Integer.parseInt(durationMatcher.group(3));
				long dec = Integer.parseInt(durationMatcher.group(4));
				duration = dec * 100L + seconds * 1000L + minutes * 60L * 1000L
						+ hours * 60L * 60L * 1000L;
				// String startTime = durationMatcher.group(5) + "ms";
				musicBitrate = Integer.parseInt(durationMatcher.group(6));
			}
			// 匹配音频采样率等信息
			if (musicStreamMatcher.find())
			{
				musicFormat = musicStreamMatcher.group(1); // 提取音频格式
				// String s2 = videoMusicStreamMatcher.group(2);
				samplerate = Long.parseLong(musicStreamMatcher.group(3)); // 提取采样率
				// String s4 = videoMusicStreamMatcher.group(4);
				// String s5 = videoMusicStreamMatcher.group(5);
				musicBitrate = Integer.parseInt(musicStreamMatcher.group(6)); // 提取比特率
			}
		} catch (Exception e)
		{
			LogTools.error("--- 解析音频参数信息出错！ --- 错误信息： " + e.getMessage());
			return null;
		}

		// 封装视频中的音频信息
		MusicMetaInfo musicMetaInfo = new MusicMetaInfo();
		musicMetaInfo.setFormat(musicFormat);
		musicMetaInfo.setDuration(duration);
		musicMetaInfo.setBitRate(musicBitrate);
		musicMetaInfo.setSampleRate(samplerate);
		musicMetaInfo.setSize(musicSize);
		return musicMetaInfo;
	}

	/**
	 * 获取音频的基本信息（从流中）
	 *
	 * @param inputStream 源音乐流路径
	 * @return 音频基本信息，解码出错时返回null
	 */
	public static MusicMetaInfo getMusicMetaInfo(InputStream inputStream)
	{
		MusicMetaInfo musicMetaInfo = new MusicMetaInfo();
		try
		{
			File file = File.createTempFile("tmp", null);
			if (!file.exists())
			{
				return null;
			}
			FileTools.copyInputStreamToFile(inputStream, file);
			musicMetaInfo = getMusicMetaInfo(file);
			file.deleteOnExit();
			return musicMetaInfo;
		} catch (Exception e)
		{
			LogTools.error("--- 从流中获取音频基本信息出错 --- 错误信息： " + e.getMessage());
			return null;
		}
	}

	//	/**
	//	 * 获取图片的基本信息（从流中）
	//	 *
	//	 * @param inputStream 源图片路径
	//	 * @return 图片的基本信息，获取信息失败时返回null
	//	 */
	//	public static ImageMetaInfo getImageInfo(InputStream inputStream)
	//	{
	//		BufferedImage image = null;
	//		ImageMetaInfo imageInfo = new ImageMetaInfo();
	//		try
	//		{
	//			image = ImageIO.read(inputStream);
	//			imageInfo.setWidth(image.getWidth());
	//			imageInfo.setHeight(image.getHeight());
	//			imageInfo.setSize(
	//					Long.valueOf(String.valueOf(inputStream.available())));
	//			return imageInfo;
	//		} catch (Exception e)
	//		{
	//			LogTools.error("--- 获取图片的基本信息失败 --- 错误信息： " + e.getMessage());
	//			return null;
	//		}
	//	}

	//	/**
	//	 * 获取图片的基本信息 （从文件中）
	//	 *
	//	 * @param imageFile 源图片路径
	//	 * @return 图片的基本信息，获取信息失败时返回null
	//	 */
	//	public static ImageMetaInfo getImageInfo(File imageFile)
	//	{
	//		BufferedImage image = null;
	//		ImageMetaInfo imageInfo = new ImageMetaInfo();
	//		try
	//		{
	//			if (null == imageFile || !imageFile.exists())
	//			{
	//				return null;
	//			}
	//			image = ImageIO.read(imageFile);
	//			imageInfo.setWidth(image.getWidth());
	//			imageInfo.setHeight(image.getHeight());
	//			imageInfo.setSize(imageFile.length());
	//			imageInfo.setFormat(TextTools.getFileExt(imageFile.getName()));
	//			return imageInfo;
	//		} catch (Exception e)
	//		{
	//			LogTools.error("--- 获取图片的基本信息失败 --- 错误信息： " + e.getMessage());
	//			return null;
	//		}
	//	}

	/**
	 * 检查文件类型是否是给定的类型
	 *
	 * @param inputFile   源文件
	 * @param givenFormat 指定的文件类型；例如：{"MP4", "AVI"}
	 */
	public static boolean isGivenFormat(File inputFile, String[] givenFormat)
	{
		if (null == inputFile || !inputFile.exists())
		{
			LogTools.error("--- 无法检查文件类型是否满足要求，因为要检查的文件不存在 --- 源文件： "
					+ inputFile);
			return false;
		}
		if (null == givenFormat || givenFormat.length == 0)
		{
			LogTools.error("--- 无法检查文件类型是否满足要求，因为没有指定的文件类型 ---");
			return false;
		}
		String format = TextTools.getFileExt(inputFile.getName());
		return isLegalFormat(format, givenFormat);
	}

	/**
	 * 使用FFmpeg的"-i"命令来解析视频信息
	 *
	 * @param inputFile 源媒体文件
	 * @return 解析后的结果字符串，解析失败时为空
	 */
	public static String getMetaInfoFromFFmpeg(File inputFile)
	{
		if (inputFile == null || !inputFile.exists())
		{
			throw new RuntimeException("源媒体文件不存在，源媒体文件路径： ");
		}
		List<String> command = new ArrayList<>();
		command.add("-i");
		command.add(inputFile.getAbsolutePath());
		return executeCommand(command);
	}

	/**
	 * 检测视频格式是否合法
	 */
	private static boolean isLegalFormat(String format, String[] formats)
	{
		if (format == null)
			return false;
		format = format.toUpperCase(Locale.ENGLISH);
		for (String item : formats)
			if (item.equals(format))
				return true;
		return false;
	}

	/**
	 * 用于取出ffmpeg线程执行过程中产生的各种输出和错误流的信息
	 */
	static class PrintStream extends Thread
	{
		InputStream inputStream;
		BufferedReader bufferedReader = null;
		StringBuffer stringBuffer = new StringBuffer();

		public PrintStream(InputStream inputStream)
		{
			this.inputStream = inputStream;
		}

		@Override
		public void run()
		{
			try
			{
				if (null == inputStream)
				{
					LogTools.error("--- 读取输出流出错！因为当前输出流为空！---");
				}
				bufferedReader = new BufferedReader(
						new InputStreamReader(inputStream));
				String line;
				while ((line = bufferedReader.readLine()) != null)
				{
					LogTools.info(line);
					stringBuffer.append(line);
				}
			} catch (Exception e)
			{
				LogTools.error("--- 读取输入流出错了！--- 错误信息：" + e.getMessage());
			} finally
			{
				try
				{
					if (null != bufferedReader)
					{
						bufferedReader.close();
					}
					if (null != inputStream)
					{
						inputStream.close();
					}
				} catch (IOException e)
				{
					LogTools.error("--- 调用PrintStream读取输出流后，关闭流时出错！---");
				}
			}
		}
	}
}